﻿using Autofac;
using Autofac.Core;
using Microsoft.Extensions.Configuration;
using Serilog;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text;
using Yitter.IdGenerator;
using YWM.Common.Extensions;
using YWM.DependencyInjection;

namespace YWM
{
    public static class YApp
    {
        /// <summary>
        /// 程序配置
        /// </summary>
        public static IConfiguration Configuration { get; private set; }

        /// <summary>
        /// 依赖注入容器
        /// </summary>
        private static IContainer _container;

        #region 注册
        /// <summary>
        /// 创建依赖注入生成器
        /// </summary>
        /// <returns></returns>
        public static MyContainerBuilder CreateBuilder(Action<ContainerBuilder> beforeBuildAction = null)
        {
            MyContainerBuilder builder = new MyContainerBuilder();
            builder.BeforeBuildAction = beforeBuildAction;
            return builder;
        }

        /// <summary>
        /// 初始化并创建依赖注入容器
        /// </summary>
        /// <typeparam name="TStartupModule"></typeparam>
        /// <param name="builder"></param>
        /// <param name="isClientServer"></param>
        /// <returns></returns>
        public static IContainer Build<TStartupModule>(this MyContainerBuilder builder, bool isClientServer = false) where TStartupModule : BaseModule
        {
            //获取并注册配置
            Configuration = GetConfiguration();
            builder.RegisterInstance(Configuration);
            //注册默认接口和类
            Assembly entryAssembly = Assembly.GetEntryAssembly();
            string suffix = Configuration["LocalizationSettings:Suffix"];
            if (suffix.IsNullOrWhiteSpace())
            {
                suffix = "Resources.Lang";
            }
            ResourceManager rm = new ResourceManager($"{entryAssembly.GetName().Name}.{suffix}", entryAssembly);
            if (rm != null)
            {
                builder.RegisterInstance(rm);
            }
            ushort workerId = Configuration.GetSection("IdGeneratorOptions").GetValue<ushort>("WorkerId");
            IdGeneratorOptions options = new IdGeneratorOptions(workerId);
            YitIdHelper.SetIdGenerator(options);
            _container = builder.Build<TStartupModule>(isClientServer);
            return _container;
        }

        /// <summary>
        /// 获取程序配置对象
        /// </summary>
        /// <returns></returns>
        /// <exception cref="FileNotFoundException"></exception>
        private static IConfiguration GetConfiguration()
        {
            IEnumerable<string> filenames = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory)
                .Where(filename => filename.EndsWith(".json") && !filename.EndsWith("\\ywmsettings.json"));
            ConfigurationBuilder builder = new ConfigurationBuilder();
            builder.AddJsonFile("ywmsettings.json", true, true);
            foreach (string filename in filenames)
            {
                if (!filename.EndsWith(".deps.json") && !filename.EndsWith(".runtimeconfig.json"))
                {
                    builder.AddJsonFile(filename, true, true);
                }
            }
            IConfiguration configuration = builder.Build();
            return configuration;
        }

        /// <summary>
        /// 设置Serilog配置委托
        /// </summary>
        /// <param name="loggerConfig"></param>
        public static MyContainerBuilder SetSerilogConfigAction(this MyContainerBuilder builder, Action<LoggerConfiguration> loggerConfigAction = null)
        {
            if (loggerConfigAction != null)
            {
                builder.LoggerConfigAction = loggerConfigAction;
                return builder;
            }

            builder.LoggerConfigAction = loggerConfig =>
            {
                string date = DateTime.Now.ToString("yyyyMMdd");
                IConfiguration configuration = Configuration;
                IConfigurationSection configurationSection = configuration.GetSection("Serilog");
                string outputTemplate = configurationSection.GetValue<string>("OutputTemplate");
                if (outputTemplate.IsNullOrWhiteSpace())
                {
                    outputTemplate = "{NewLine}{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}";
                }
                outputTemplate += new string('-', 100);
                bool rollOnFileSizeLimit = configurationSection.GetValue<bool>("RollOnFileSizeLimit");
                bool isOutputConsole = configurationSection.GetValue<bool>("IsOutputConsole");
                loggerConfig.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(evt => evt.Level != LogEventLevel.Error).WriteTo.File($"Logs/{date}/.log", rollingInterval: RollingInterval.Day, outputTemplate: outputTemplate, rollOnFileSizeLimit: rollOnFileSizeLimit, encoding: Encoding.UTF8));
                loggerConfig.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(evt => evt.Level == LogEventLevel.Error).WriteTo.File($"Logs/{date}/{LogEventLevel.Error}.log", outputTemplate: outputTemplate, rollingInterval: RollingInterval.Day, encoding: Encoding.UTF8));
                if (isOutputConsole)
                {
                    loggerConfig.WriteTo.Console(outputTemplate: outputTemplate);
                }
            };
            return builder;
        }
        #endregion

        #region 解析
        public static ServiceType Resolve<ServiceType>(params Parameter[] parameters)
        {
            if (_container == null)
            {
                return default(ServiceType);
            }
            return _container.Resolve<ServiceType>(parameters);
        }

        public static object Resolve(Type serviceType, params Parameter[] parameters)
        {
            if (_container == null)
            {
                return null;
            }
            return _container.Resolve(serviceType, parameters);
        }

        public static bool IsRegistered<ServiceType>()
        {
            if (_container == null)
            {
                return false;
            }
            return _container.IsRegistered<ServiceType>();
        }

        public static bool IsRegistered(Type serviceType)
        {
            if (_container == null)
            {
                return false;
            }
            return _container.IsRegistered(serviceType);
        }
        #endregion

        /// <summary>
        /// 开始范围生命周期
        /// </summary>
        /// <returns></returns>
        public static ILifetimeScope BeginLifetimeScope()
        {
            return _container.BeginLifetimeScope();
        }
    }
}
